package com.hj.util;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;
import com.hj.config.ConfigConstants;
import com.hj.model.FileAttribute;
import com.hj.model.FileType;

/**
 * @author dehui dou
 * @date 2020/10/3 19:36
 * @description 文件工具类
 */
public class FileUtils {

    private static final String DEFAULT_CONVERTER_CHARSET = System.getProperty("sun.jnu.encoding");

    /**
     * 查看文件类型(防止参数中存在.点号或者其他特殊字符，所以先抽取文件名，然后再获取文件类型)
     *
     * @param url
     *            url
     * @return 文件类型
     */
    public static FileType typeFromUrl(String url) {
        String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
        String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
        return typeFromFileName(fileName);
    }

    private static FileType typeFromFileName(String fileName) {
        String[] simText = ConfigConstants.getSimText();
        String[] media = ConfigConstants.getMedia();
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
        if (listPictureTypes().contains(fileType.toLowerCase())) {
            return FileType.picture;
        }
        if (listArchiveTypes().contains(fileType.toLowerCase())) {
            return FileType.compress;
        }
        if (listOfficeTypes().contains(fileType.toLowerCase())) {
            return FileType.office;
        }
        if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
            return FileType.simText;
        }
        if (Arrays.asList(media).contains(fileType.toLowerCase())) {
            return FileType.media;
        }
        if ("pdf".equalsIgnoreCase(fileType)) {
            return FileType.pdf;
        }
        if ("dwg".equalsIgnoreCase(fileType)) {
            return FileType.cad;
        }
        return FileType.other;
    }

    public static FileType typeFromFileFormat(String format) {
        String[] simText = ConfigConstants.getSimText();
        String[] media = ConfigConstants.getMedia();
        if (listPictureTypes().contains(format.toLowerCase())) {
            return FileType.picture;
        }
        if (listArchiveTypes().contains(format.toLowerCase())) {
            return FileType.compress;
        }
        if (listOfficeTypes().contains(format.toLowerCase())) {
            return FileType.office;
        }
        if (Arrays.asList(simText).contains(format.toLowerCase())) {
            return FileType.simText;
        }
        if (Arrays.asList(media).contains(format.toLowerCase())) {
            return FileType.media;
        }
        if ("pdf".equalsIgnoreCase(format)) {
            return FileType.pdf;
        }
        if ("dwg".equalsIgnoreCase(format)) {
            return FileType.cad;
        }
        return FileType.other;
    }

    /**
     * 从url中剥离出文件名
     *
     * @param url
     *            格式如：http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I
     *            D1NOFtAJSPT16E6imv6JWuq0k=
     * @return 文件名
     */
    public static String getFileNameFromURL(String url) {
        // 因为url的参数中可能会存在/的情况，所以直接url.lastIndexOf("/")会有问题
        // 所以先从？处将url截断，然后运用url.lastIndexOf("/")获取文件名
        String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
        return noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1);
    }

    /**
     * 从路径中获取文件
     *
     * @param path
     *            类似这种：C:\Users\yudian-it\Downloads
     * @return 文件名
     */
    public static String getFileNameFromPath(String path) {
        return path.substring(path.lastIndexOf(File.separator) + 1);
    }

    public static List<String> listPictureTypes() {
        List<String> list = Lists.newArrayList();
        list.add("jpg");
        list.add("jpeg");
        list.add("png");
        list.add("gif");
        list.add("bmp");
        list.add("ico");
        list.add("RAW");
        return list;
    }

    public static List<String> listArchiveTypes() {
        List<String> list = Lists.newArrayList();
        list.add("rar");
        list.add("zip");
        list.add("jar");
        list.add("7-zip");
        list.add("tar");
        list.add("gzip");
        list.add("7z");
        return list;
    }

    public static List<String> listOfficeTypes() {
        List<String> list = Lists.newArrayList();
        list.add("docx");
        list.add("doc");
        list.add("xls");
        list.add("xlsx");
        list.add("ppt");
        list.add("pptx");
        return list;
    }

    /**
     * 获取相对路径
     *
     * @param absolutePath
     *            绝对路径
     * @return 相对路径
     */
    public static String getRelativePath(String absolutePath) {
        return absolutePath.substring(ConfigConstants.getFileDir().length());
    }

    /**
     * 判断文件编码格式
     *
     * @param path
     *            绝对路径
     * @return 编码格式
     */
    public static String getFileEncodeUTFGBK(String path) {
        String enc = Charset.forName("GBK").name();
        File file = new File(path);
        InputStream in;
        try {
            in = new FileInputStream(file);
            byte[] b = new byte[3];
            in.read(b);
            in.close();
            if (b[0] == -17 && b[1] == -69 && b[2] == -65) {
                enc = StandardCharsets.UTF_8.name();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return enc;
    }

    /**
     * 对转换后的文件进行操作(改变编码方式)
     *
     * @param outFilePath
     *            文件绝对路径
     */
    public static void doActionConvertedFile(String outFilePath) {
        StringBuilder sb = new StringBuilder();
        try (InputStream inputStream = new FileInputStream(outFilePath);
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, DEFAULT_CONVERTER_CHARSET))) {
            String line;
            while (null != (line = reader.readLine())) {
                if (line.contains("charset=gb2312")) {
                    line = line.replace("charset=gb2312", "charset=utf-8");
                }
                sb.append(line);
            }
            // 添加sheet控制头
            sb.append("<script src=\"js/jquery-3.0.0.min.js\" type=\"text/javascript\"></script>");
            sb.append("<script src=\"js/excel.header.js\" type=\"text/javascript\"></script>");
            sb.append("<link rel=\"stylesheet\" href=\"bootstrap/css/bootstrap.min.css\">");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 重新写入文件
        try (FileOutputStream fos = new FileOutputStream(outFilePath);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
            writer.write(sb.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取文件后缀
     *
     * @param url
     *            url
     * @return 文件后缀
     */
    private static String suffixFromUrl(String url) {
        String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
        String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
        return suffixFromFileName(fileName);
    }

    private static String suffixFromFileName(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * 获取url中的参数
     *
     * @param url
     *            url
     * @param name
     *            参数名
     * @return 参数值
     */
    public static String getUrlParameterReg(String url, String name) {
        Map<String, String> mapRequest = new HashMap<>();
        String strUrlParam = truncateUrlPage(url);
        if (strUrlParam == null) {
            return "";
        }
        // 每个键值为一组
        String[] arrSplit = strUrlParam.split("[&]");
        for (String strSplit : arrSplit) {
            String[] arrSplitEqual = strSplit.split("[=]");
            // 解析出键值
            if (arrSplitEqual.length > 1) {
                // 正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
            } else if (!arrSplitEqual[0].equals("")) {
                // 只有参数没有值，不加入
                mapRequest.put(arrSplitEqual[0], "");
            }
        }
        return mapRequest.get(name);
    }

    /**
     * 去掉url中的路径，留下请求参数部分
     *
     * @param strURL
     *            url地址
     * @return url请求参数部分
     */
    private static String truncateUrlPage(String strURL) {
        String strAllParam = null;
        strURL = strURL.trim();
        String[] arrSplit = strURL.split("[?]");
        if (strURL.length() > 1) {
            if (arrSplit.length > 1) {
                if (arrSplit[1] != null) {
                    strAllParam = arrSplit[1];
                }
            }
        }
        return strAllParam;
    }

    /**
     * 获取文件属性
     *
     * @param url
     *            url
     * @return 文件属性
     */
    public static FileAttribute getFileAttribute(String url) {
        String fileName;
        FileType type;
        String suffix;
        String fullFileName = getUrlParameterReg(url, "fullfilename");
        if (!StringUtils.isEmpty(fullFileName)) {
            fileName = fullFileName;
            type = typeFromFileName(fileName);
            suffix = suffixFromFileName(fileName);
        } else {
            fileName = getFileNameFromURL(url);
            type = typeFromUrl(url);
            suffix = suffixFromUrl(url);
        }
        return new FileAttribute(type, suffix, fileName, url);
    }

    public static void saveBytesToFile(byte[] b, File file) {
        OutputStream os = null;
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            os = new FileOutputStream(file);
            os.write(b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @author dehui dou
     * @description 数据保存到文件
     * @date 2020/9/29 11:07
     * @params [content, filePath]
     */
    public static void savaStringToFile(String content, String filePath) {
        BufferedWriter output = null;
        try {
            File f = new File(filePath);
            if (!f.exists()) {
                f.createNewFile();
            }
            output = new BufferedWriter(new FileWriter(f));
            output.write(content);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @author dehui dou
     * @description 读取文件数据
     * @date 2020/9/29 11:07
     * @params [filePath]
     */
    public static String readFile(String filePath) {
        String result = "";
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            fileReader = new FileReader(filePath);
            bufferedReader = new BufferedReader(fileReader);
            try {
                String read = null;
                while ((read = bufferedReader.readLine()) != null) {
                    result = result + read;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * @author dehui dou
     * @description 删除转换过的文件,针对url方式预览的情况
     * @param fileName
     * @return void
     */
    public static void delFile(String fileName) {
        String fileUniqueId = fileName.substring(0, fileName.indexOf("."));
        String type = fileName.substring(fileName.indexOf(".") + 1);
        List<String> delFilePathList = new ArrayList();
        delFilePathList.add(ConfigConstants.getFileDir() + fileName);
        delFilePathList.add(ConfigConstants.getFileDir() + fileUniqueId);
        delFilePathList.add(ConfigConstants.getFileDir() + fileUniqueId + ".pdf");
        // 压缩文件，递归查询
        if (listArchiveTypes().contains(type)) {
            String compressDir = ConfigConstants.getFileDir() + fileUniqueId;
            File file = new File(compressDir);
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (int i = 0; i < files.length; i++) {
                    if (!files[i].isDirectory()) {
                        String name = files[i].getName();
                        String extension = name.substring(name.indexOf(".") + 1);
                        if (listArchiveTypes().contains(extension)) {
                            delFile(name);
                        }
                    }
                }
            }
        }
        // 执行删除
        for (String path : delFilePathList) {
            File file = new File(path);
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files != null && files.length > 0) {
                    for (int i = 0; i < files.length; i++) {
                        files[i].delete();
                    }
                }
                file.delete();
            } else {
                file.delete();
            }
        }
    }

    /**
     * @author dehui dou
     * @description 删除文件预览目录下所有文件,job执行时
     * @param file
     * @return void
     */
    public static void delAllViewFile(File file) {
        if (!file.exists()) {
            return;
        }
        if (file.isFile() || file.list() == null) {
            file.delete();
        } else {
            File[] files = file.listFiles();
            for (File a : files) {
                delAllViewFile(a);
            }
            file.delete();
        }

    }

}
